package com.ns.school.common.utils;

import com.ns.school.common.constant.StaticVar;
import com.ns.school.common.exception.MyException;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 加密工具
 *
 * @author Spark
 */
public class AESUtil {

    private static final Logger log = LoggerFactory.getLogger(AESUtil.class);

    /**
     * 加密-核心
     *
     * @param key
     * @param value
     * @return
     */
    public static String encryption(String key, String value) {
        try {
            if (StrUtil.isEmpty(value)) {
                log.info("被加密对象为空");
                return null;
            }
            if (StrUtil.isEmpty(key)) {
                log.info("加密key为空");
                return null;
            }
            return Objects.requireNonNull(encryptCore(key, value.getBytes(StandardCharsets.UTF_8))).replaceAll("[\r\n]", StaticVar.EMPTY);
        } catch (Exception e) {
            MyException.print(log, e);
        }
        return null;
    }

    /**
     * 加密
     *
     * @param key
     * @param value
     * @return
     */
    public static String encryption(String key, Integer value) {
        if (value == null) {
            return null;
        }
        return encryption(key, value.toString());
    }

    /**
     * 加密
     *
     * @param key
     * @param value
     * @return
     */
    public static String encryption(String key, Long value) {
        if (value == null) {
            return null;
        }
        return encryption(key, value.toString());
    }

    /**
     * 解密-核心
     *
     * @param key
     * @param value
     * @return
     */
    public static String decryption(String key, String value) {
        try {
            if (StrUtil.isEmpty(value)) {
                log.info("被解密对象为空");
                return null;
            } else if ("null".equals(value)) {
                log.info("被解密对象为null");
                return null;
            }
            if (StrUtil.isEmpty(key)) {
                log.info("解密key为空");
                return null;
            }
            if (value.contains(StaticVar.PERCENT)) {
                return decryptCore(key, URLDecoder.decode(value, StandardCharsets.UTF_8));
            } else {
                return decryptCore(key, value);
            }
        } catch (Exception e) {
            MyException.print(log, e);
        }
        return null;
    }

    public static Integer decryptionInteger(String key, String value) {
        String decodeStr = decryption(key, value);
        if (StrUtil.notEmpty(decodeStr)) {
            try {
                return Integer.valueOf(decodeStr);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    public static Long decryptionLong(String key, String value) {
        String decodeStr = decryption(key, value);
        if (StrUtil.notEmpty(decodeStr)) {
            try {
                return Long.valueOf(decodeStr);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    private static final String AES = "AES";
    private static final String CIPHER_MODE_PADDING = "AES/CBC/PKCS5Padding";// 算法/模式/补码方式
    private static final byte[] IV = {0xE, 2, 0xD, 12, 3, 0xA, 5, 2, 0x17, 5, 1, 11, 15, 0xB, 0xF, 16};

    /**
     * 加密
     *
     * @param key
     * @param text
     * @return
     */
    public static String encryptCore(String key, byte[] text) {
        try {
            byte[] skAsByteArray = key.getBytes();
            SecretKeySpec skforAES = new SecretKeySpec(skAsByteArray, AES);
            IvParameterSpec iv = new IvParameterSpec(IV);// 使用CBC模式，需要一个向量iv，可增加加密算法的强度

            Cipher c = Cipher.getInstance(CIPHER_MODE_PADDING);
            c.init(Cipher.ENCRYPT_MODE, skforAES, iv);

            return new String(new Base64(true).encode(c.doFinal(text)), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("加密失败:{}", e.getMessage());
        }
        return null;
    }

    /**
     * 解密
     *
     * @param key
     * @param text
     * @return
     */
    public static String decryptCore(String key, String text) {
        try {
            byte[] skAsByteArray = key.getBytes();
            SecretKeySpec skforAES = new SecretKeySpec(skAsByteArray, AES);
            IvParameterSpec iv = new IvParameterSpec(IV);// 使用CBC模式，需要一个向量iv，可增加加密算法的强度

            Cipher c = Cipher.getInstance(CIPHER_MODE_PADDING);
            c.init(Cipher.DECRYPT_MODE, skforAES, iv);

            return new String(c.doFinal(new Base64(true).decode(text)), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("解密失败:{}", e.getMessage());
        }
        return null;
    }

    public static void main(String[] args) {
        String key = Md5Util.getMD5("x5i7xt4%&3$Nf8w#I44");
        String val = encryption(key, "1125641");// 加密
        System.out.println(val);
        System.out.println(decryption(key, val));// 解密
    }
}
